{% extends 'core/Broken Access Control/broken-access.html' %} {% load static %}
Preventing this issue is easier than it may seem. For Broken Access prevention, we will use authentication.
What I recommend the most is using libraries. Many big frameworks have built-in libraries that take care of
it for us. This website uses UserCreationForm, AuthenticationForm for Django.
Other examples may include PHP OAuth 2.0 Server for PHP, Microsoft Authentication Library (MSAL) for .NET
, and many others.
First, let's see what we are even doing. You can see this as an anonymous user without any authorization.
First, create an account on the Sign up page you can use for testing, for example:
As you can see, once we logged in, a new tab appeared. This is an example of prevention against Broken Access Control. You can also try to log out and access the following:
http://127.0.0.1:8000/profile
After accessing the URL without authentication, users will be automatically rerouted to the main page. Now let us look at how to implement it.
To display our content only to selected people, we first need a way to distinguish logged-in users from anonymous browsers. For that, we implement a log-in/register system. We start that off by making a simple database. Some frameworks like Django will generate their structure, lessening your workload. But let's assume you need to do it yourself.
As you can see, this is an exemplary structure you could use for your project, obviously adding or removing
tables based on your needs. Take a note of some important columns like - is_superuser. This is, again, Django's
way of checking admin authentication—however, a good practice in any other project. If you require more
permission levels, you could add a column with the same name and instead use Integers. Now that we can see if
a user can access certain pages or not, let's use it.
First, we need a code to check whether users accessing specific URLs are authenticated. This will be
explained in general terms, as it would be a whole other topic if we were to code the entire implementation.
To authenticate our users, we will allow them to register. Registration and login are usually done through
forms.
Example:
<form method="post">
{ csrf_token }
{% for field in form %}
<p>
{{ field.label_tag }}
{{ field }}
{% for error in field.errors %;}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" class="btn btn-success">Sign up</button>
</form>
Here you can see an example of registration forms. We loop through fields in the forms. Forms contain three fields, username, password, and password confirmation. Similarly, we loop through errors if the sign-up fails. field.label_tag displays name of each field. You can see how these variables are bound to our views file in the step below.
The form displays the predefined username, password, and password confirmation fields in this example. Same
would be used for user login.
Now we have a way to get input from our user; we need a backend logic that will make queries to our database
to see if this user already exists.
Example of a query:
SELECT * FROM testDatabase.auth_user WHERE username="user1";
Queries like these allow us to check if the user already exists. If it does, we can authorize and log him in. However, our queries look a bit different. You can check that in the Injections tutorial.
def signup(request):
if request.user.is_authenticated:
return redirect('/')
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
return render(request, 'core/signup.html', {'form': form})
else:
form = UserCreationForm()
return render(request, 'core/signup.html', {'form': form})
Since we want only one type of request on our sign-up page, we first check if the incoming communication is
POST. If so, we read the username and password fields and create a form. The "UserCreationForm" function
checks if the credentials are correct, such as if the username doesn't exist or if the password follows all
necessary validators. If credentials pass all the checks, we create the form. If not, we return the form
containing the error message. A valid form will be saved into the website's database. After that, we take
the username and password from the valid form, authenticate and log the user in. This process is similar to
log-in except for creating the form.
Now that we have verified our user, we need to foolproof where he can get access. The image at the top being used as an example.
In this last step, we will condition all the views/URLs we want to separate from non-logged-in users. Since we now know when users are logged in, we can easily separate them. Such as:
{% if user.is_authenticated %}
<li>
<a href="/profile"
</li>
{% endif %}
This is a simple front-end check with an "if" condition that only displays the profile tab to authenticated users. However, if we were only to condition it on the front end, it could still be accessed through URL change /profile. So let's see how to prevent that.
def profile(request):
if request.user.is_authenticated:
return render(request, 'core/Profile.html')
else:
return redirect('/')
In the views, we define a simple method to get called each time somebody clicks our /profile link. The check is the same as in the front end, but we return our profile view here. If the user's authentication fails, he gets rerouted to the homepage.